
local o = MapReveal;

-- Overrides_t_Init: ()
-- Overrides_OnEvent_VARIABLES_LOADED: ()
-- Overrides_t_Hook_WorldMapFrame_Update: ()
--
-- Overrides_ToggleRevealing: (enable)
-- Overrides_ToggleShading: (enable)
--
-- Overrides_AddMissingOverlays: (zoneName, overlaysArray)
	-- Overrides_CreateMissingOverlays_DefaultWorldMap: (overlaysArray, numNeeded)
-- Overrides_SetupOverlay: overlayIndex = (overlayIndex, overlaysArray, overlaysCreationFunc, textureName, textureWidth, textureHeight, offsetX, offsetY, r, g, b)
-- Overrides_UnshadeShownOverlays: lastShown = (overlaysArray)

-- Overrides_STATIC_DATA = {};

-- saved = MapReveal_SavedData;
o.Overrides_cachedDefaultOverlaysArray = {};
do
	local rawget = rawget;
	local _G = _G;
	setmetatable(o.Overrides_cachedDefaultOverlaysArray, {
		__index = (function(self, key)
			for index = NUM_WORLDMAP_OVERLAYS, (#self + 1), -1 do
				self[index] = _G["WorldMapOverlay" .. index];
			end
			return rawget(self, key);
		end);
	});
end




function o.Overrides_t_Init()
	o.Overrides_t_Init = nil;
	
	o.Overrides_t_Hook_WorldMapFrame_Update();
	
	local revealCB = CreateFrame("CheckButton", "MapReveal_RevealAreasCB", WorldMapFrame, "OptionsCheckButtonTemplate");
	revealCB:SetWidth(32);
	revealCB:SetHeight(32);
	revealCB:SetHitRectInsets(0, -50, 0, 0);
	revealCB:SetPoint("TOPRIGHT", WorldMapFrame, "TOPRIGHT", -600, -185);
	revealCB:SetScript("PostClick", (function() o.Overrides_ToggleRevealing(); end));
	MapReveal_RevealAreasCBText:SetText(ENABLE .. " MapReveal");
	
	local shadeCB = CreateFrame("CheckButton", "MapReveal_ShadeUndiscoveredCB", WorldMapFrame, "OptionsCheckButtonTemplate");
	shadeCB:SetWidth(24);
	shadeCB:SetHeight(24);
	shadeCB:SetHitRectInsets(0, -50, 0, 0);
	shadeCB:SetPoint("TOPLEFT", revealCB, "BOTTOMLEFT", 10, 5);
	shadeCB:SetScript("PostClick", (function() o.Overrides_ToggleShading(); end));
	MapReveal_ShadeUndiscoveredCBText:SetText(o.Localization.SHADE_UNDISCOVERED);
	
	revealCB:RegisterEvent("VARIABLES_LOADED");
	revealCB:SetScript("OnEvent", o.Overrides_OnEvent_VARIABLES_LOADED);
end



function o.Overrides_OnEvent_VARIABLES_LOADED()
	o.Overrides_OnEvent_VARIABLES_LOADED = nil;
	local cb = MapReveal_RevealAreasCB;
	cb:UnregisterEvent("VARIABLES_LOADED");
	cb:SetScript("OnEvent", nil);
	
	local saved = MapReveal_SavedData;
	if (saved == nil) then
		saved = {
			revealingDisabled = nil;
			shadingDisabled = nil;
			errata = nil;
		};
		MapReveal_SavedData = saved;
	else
		if (saved.noShade ~= nil) then
			saved.noShade = nil;
			saved.shadingDisabled = true;
		end
	end
	o.saved = saved;
	
	local errata = saved.errata;
	if (errata ~= nil) then
		local staticZoneData;
		local areaData, pos, foundErrata;
		for zoneName, zoneData in pairs(errata) do
			if (type(zoneData) == "string") then
				staticZoneData = o.Overrides_STATIC_DATA[zoneName];
				if (staticZoneData ~= nil) then
					foundErrata = false;
					areaData, pos = zoneData:match("(............[^~]+)~?()", 1);
					while (areaData ~= nil and foundErrata == false) do
						if (staticZoneData:find(areaData:NicheDevTools_EscapePatterns()) == nil) then
							foundErrata = true;
						else
							areaData, pos = zoneData:match("(............[^~]+)~?()", pos);
						end
					end
				else
					foundErrata = true;
				end
				if (foundErrata == true) then
					o.Overrides_STATIC_DATA[zoneName] = zoneData;
				else
					errata[zoneName] = nil;
				end
			else
				errata[zoneName] = nil;
			end
		end
		if (next(errata) == nil) then
			saved.errata = nil;
		end
	end
	
	MapReveal_RevealAreasCB:SetChecked(not saved.revealingDisabled);
	MapReveal_ShadeUndiscoveredCB:SetChecked(not saved.shadingDisabled);
end



function o.Overrides_t_Hook_WorldMapFrame_Update()
	o.Overrides_t_Hook_WorldMapFrame_Update = nil;
	
	hooksecurefunc("WorldMapFrame_Update", function()
		if (o.saved.revealingDisabled ~= true) then
			o.Overrides_AddMissingOverlays(GetMapInfo(), o.Overrides_cachedDefaultOverlaysArray);
		end
	end);
end




function o.Overrides_ToggleRevealing(enable)
	if (enable == nil) then
		enable = (not not o.saved.revealingDisabled);
	end
	enable = ((enable and true) or nil);
	
	o.saved.revealingDisabled = ((enable == nil and true) or nil);
	if (WorldMapFrame:IsShown() ~= nil) then
		if (enable ~= true) then
			o.Overrides_UnshadeShownOverlays(o.Overrides_cachedDefaultOverlaysArray);
		end
		WorldMapFrame_Update();
	end
end



function o.Overrides_ToggleShading(enable)
	if (enable == nil) then
		enable = (not not o.saved.shadingDisabled);
	end
	enable = ((enable and true) or nil);
	
	o.saved.shadingDisabled = ((enable == nil and true) or nil);
	if (WorldMapFrame:IsShown() ~= nil) then
		if (enable ~= true) then
			o.Overrides_UnshadeShownOverlays(o.Overrides_cachedDefaultOverlaysArray);
		end
		WorldMapFrame_Update();
	end
end




function o.Overrides_AddMissingOverlays(zoneName, overlaysArray)
	local GetMapOverlayInfo = GetMapOverlayInfo;
	local StoreAreaErrata = o.Overrides_StoreAreaErrata;
	local realOverlayAreaNames = nil;
	
	local textureName, textureWidth, textureHeight, offsetX, offsetY;
	local loopZoneName, loopAreaName;
	for index = 1, GetNumMapOverlays(), 1 do
		textureName, textureWidth, textureHeight, offsetX, offsetY = GetMapOverlayInfo(index);
		loopZoneName, loopAreaName = textureName:match("^Interface\\WorldMap\\([^\\]+)\\(.+)$");
		if (loopAreaName ~= nil) then
			if (realOverlayAreaNames == nil) then
				realOverlayAreaNames = {};
			end
			realOverlayAreaNames[loopAreaName] = true;
			StoreAreaErrata(loopZoneName, loopAreaName, textureWidth, textureHeight, offsetX, offsetY);
		end
	end
	
	local zoneData = o.Overrides_STATIC_DATA[zoneName];
	if (zoneData == nil) then
		return;
	end
	
	local SetupOverlay = o.Overrides_SetupOverlay;
	local CreateMissingOverlays_DefaultWorldMap = o.Overrides_CreateMissingOverlays_DefaultWorldMap;
	local texturePrefix = ("Interface/WorldMap/" .. zoneName .. "/");
	local r, g, b;
	if (o.saved.shadingDisabled ~= true) then
		r, g, b = 0.7, 0.7, 0.7;
	else
		r, g, b = 1.0, 1.0, 1.0;
	end
	local overlayIndex = o.Overrides_UnshadeShownOverlays(overlaysArray);
	local textureWidth, textureHeight, offsetX, offsetY, areaName, pos = zoneData:match("(...)(...)(...)(...)([^~]+)~?()", 1);
	while (areaName ~= nil) do
		if (realOverlayAreaNames == nil or realOverlayAreaNames[areaName] == nil) then
			overlayIndex = SetupOverlay(
				overlayIndex, overlaysArray, CreateMissingOverlays_DefaultWorldMap,
				(texturePrefix .. areaName), textureWidth, textureHeight, offsetX, offsetY,
				r, g, b
			);
		end
		textureWidth, textureHeight, offsetX, offsetY, areaName, pos = zoneData:match("(...)(...)(...)(...)([^~]+)~?()", pos);
	end
end


do
	local loc_FOUND_ERRATA = o.Localization.FOUND_ERRATA;
	
	function o.Overrides_StoreAreaErrata(zoneName, areaName, textureWidth, textureHeight, offsetX, offsetY)
		-- Skip the worthless pixelfix pieces.
		if (areaName:lower() == "pixelfix") then
			return;
		end
		
		local oldZoneData = o.Overrides_STATIC_DATA[zoneName];
		local newAreaData = ("%03s%03s%03s%03s%s"):format(textureWidth, textureHeight, offsetX, offsetY, areaName);
		if (oldZoneData == nil or oldZoneData:find(newAreaData, 1, true) == nil) then
			local newZoneData;
			if (oldZoneData ~= nil) then
				if (oldZoneData:find(areaName, 1, true) ~= nil) then
					newZoneData = oldZoneData:gsub(("............" .. areaName:NicheDevTools_EscapePatterns()), newAreaData, 1);
				else
					newZoneData = (oldZoneData .. "~" .. newAreaData);
				end
			else
				newZoneData = newAreaData;
			end
			o.Overrides_STATIC_DATA[zoneName] = newZoneData;
			if (o.saved.errata == nil) then
				o.saved.errata = {};
			end
			o.saved.errata[zoneName] = newZoneData;
			DEFAULT_CHAT_FRAME:AddMessage(loc_FOUND_ERRATA:format(zoneName, areaName, textureWidth, textureHeight, offsetX, offsetY));
		end
	end
end


function o.Overrides_CreateMissingOverlays_DefaultWorldMap(overlaysArray, numNeeded)
	for index = (#overlaysArray + 1), numNeeded, 1 do
		overlaysArray[index] = WorldMapDetailFrame:CreateTexture(("WorldMapOverlay" .. index), "ARTWORK", nil);
	end
	NUM_WORLDMAP_OVERLAYS = numNeeded;
end



function o.Overrides_SetupOverlay(overlayIndex, overlaysArray, overlaysCreationFunc, textureName, textureWidth, textureHeight, offsetX, offsetY, r, g, b)
	local numTexturesWide = math.ceil(textureWidth / 256);
	local numTexturesTall = math.ceil(textureHeight / 256);
	
	local numOverlaysNeeded = (overlayIndex + (numTexturesWide * numTexturesTall));
	if (numOverlaysNeeded > #overlaysArray) then
		overlaysCreationFunc(overlaysArray, numOverlaysNeeded);
	end
	
	local numOverlays = 0;
	local overlay;
	local texturePixelHeight, texturePixelWidth, textureFileHeight, textureFileWidth;
	for tallIndex = 1, numTexturesTall, 1 do
		if (tallIndex < numTexturesTall) then
			texturePixelHeight = 256;
			textureFileHeight = 256;
		else
			texturePixelHeight = (textureHeight % 256);
			if (texturePixelHeight == 0) then
				texturePixelHeight = 256;
			end
			textureFileHeight = 16;
			while (textureFileHeight < texturePixelHeight) do
				textureFileHeight = (textureFileHeight * 2);
			end
		end
		
		for wideIndex = 1, numTexturesWide, 1 do
			numOverlays = (numOverlays + 1);
			
			if (wideIndex < numTexturesWide) then
				texturePixelWidth = 256;
				textureFileWidth = 256;
			else
				texturePixelWidth = (textureWidth % 256);
				if (texturePixelWidth == 0) then
					texturePixelWidth = 256;
				end
				textureFileWidth = 16;
				while (textureFileWidth < texturePixelWidth) do
					textureFileWidth = (textureFileWidth * 2);
				end
			end
			
			overlayIndex = (overlayIndex + 1);
			overlay = overlaysArray[overlayIndex];
			overlay:SetVertexColor(r, g, b);
			overlay:SetWidth(texturePixelWidth);
			overlay:SetHeight(texturePixelHeight);
			overlay:SetTexCoord(0, (texturePixelWidth / textureFileWidth), 0, (texturePixelHeight / textureFileHeight));
			overlay:SetPoint("TOPLEFT", (offsetX + (256 * (wideIndex - 1))), (-(offsetY + (256 * (tallIndex - 1)))));
			overlay:SetTexture(textureName .. (((tallIndex - 1) * numTexturesWide) + wideIndex));
			overlay:Show();
		end
	end
	
	return overlayIndex;
end



function o.Overrides_UnshadeShownOverlays(overlaysArray)
	local index = 1;
	local overlay = overlaysArray[1];
	while (overlay ~= nil and overlay:IsShown() ~= nil) do
		overlay:SetVertexColor(1.0, 1.0, 1.0);
		index = (index + 1);
		overlay = overlaysArray[index];
	end
	return (index - 1);
end
